package com.beaglebros.SDWatch;

import java.io.IOException;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import com.beaglebros.SDWatch.R;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.AssetManager;
import android.content.res.XmlResourceParser;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

public class SDWatch extends BroadcastReceiver {
	
	protected static final String TAG = "SDWatch";
	private Bitmap icon;
	
	// Should exist as ApplicationInfo.FLAG_FORWARD_LOCK
	// but FLAG_FORWARD_LOCK is marked as "@hide".  WHY?!?
	public static final int FLAG_FORWARD_LOCK = (1<<20);
	
	@Override
	public void onReceive(Context context, Intent intent) {
		
		String pkg = intent.getData().getEncodedSchemeSpecificPart();
		
		String displayName = canBeMoved(context, pkg);
		if (displayName != null) {
			int id;
			try {
				id = new Prefs().getId();
			} catch (BitmapOutOfBoundsException e) {
				Log.e(TAG, "too many existing notifications?");
				return;
			}
			
			Intent oi = new Intent(Intent.ACTION_VIEW);
			oi.setClassName(context, "com.beaglebros.SDWatch.NotificationClicked");
			oi.setData(Uri.fromParts("sdmovewatch", pkg, Integer.toString(id)));
			
			PendingIntent pi = PendingIntent.getBroadcast(context, 0, oi, 0);
			
			NotificationManager nm = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
			Notification n = new Notification(R.drawable.sdwatch, String.format(context.getResources().getText(R.string.notificationTicker).toString(), displayName), System.currentTimeMillis());
			n.setLatestEventInfo(context, displayName, String.format(context.getResources().getText(R.string.notificationText).toString()), pi);
			
			View v = View.inflate(context, n.contentView.getLayoutId(), null);
			ImageView iv = findImageView(v);
			
			n.contentView.setImageViewBitmap(iv.getId(), icon);
			nm.notify(id, n);
		}
	}


	private ImageView findImageView(View v) {
		if (v instanceof ViewGroup) {
			ViewGroup vg = (ViewGroup)v;
			for (int i = vg.getChildCount(); i > 0; i--) {
				ImageView rv = findImageView(vg.getChildAt(i-1));
				if (rv != null) {
					return rv;
				}
			}
			return null;
		} else if (v instanceof ImageView) {
			return (ImageView)v;
		} else {
			return null;
		}
	}
	
	
	private String canBeMoved(Context context, String packageName) {
		PackageManager pm = context.getPackageManager();
		ApplicationInfo ai;
		try {
			ai = pm.getApplicationInfo(packageName, 0);
		} catch (NameNotFoundException e1) {
			return null;
		}
		if (
		     ( ( ai.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE ) != 0 ) ||
		     ( ( ai.flags & FLAG_FORWARD_LOCK ) != 0 ) ||
		     ( ( ai.flags & ApplicationInfo.FLAG_SYSTEM ) != 0 ) ||
		     ( ( ai.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP ) != 0 )
		) {
			return null;
		}
		try {
			AssetManager am = context.createPackageContext(packageName, 0).getAssets();
			XmlResourceParser xml = am.openXmlResourceParser("AndroidManifest.xml");
			try {
				int eventType = xml.getEventType();
				xmlloop:
					while (eventType != XmlPullParser.END_DOCUMENT) {
						switch (eventType) {
						case XmlPullParser.START_TAG:
							if (! xml.getName().matches("manifest")) {
								eventType = xml.nextToken();
								continue xmlloop;
							} else {
								for (int j = 0; j < xml.getAttributeCount(); j++) {
									if (xml.getAttributeName(j).matches("installLocation")) {
										switch (Integer.parseInt(xml.getAttributeValue(j))) {
										case 0:
										case 2:
											Drawable d = ai.loadIcon(pm);
											icon = ((BitmapDrawable)d).getBitmap();
											return ai.loadLabel(pm).toString();
										default:
											return null;
										}
									}
								}
							}
							break;
						}
						eventType = xml.nextToken();
					}
			} catch (IOException ioe) {
				return null;
			} catch (XmlPullParserException xppe) {
				return null;
			}

		} catch (NameNotFoundException e) {
			return null;
		} catch (IOException e) {
			return null;
		}
		return null;
	}

}
